# 功能模块：3D引擎鼠标事件类
# 作者：dl
# 描述：鼠标点击事件单独封装

import vtk

from vtkmodules.vtkInteractionStyle import vtkInteractorStyleMultiTouchCamera
from vtkmodules.vtkRenderingCore import (
    vtkHardwareSelector
)

from vtkmodules.vtkCommonDataModel import (
    vtkSelectionNode
)

from visualizationCom.tools.color import hex_to_rgba
import random
import nest_asyncio
nest_asyncio.apply()


# pick scene-node
class SceneNodePicker(vtkHardwareSelector):
    def __init__(self) -> None:
        pass

    def Pick(self, x, y):
        self.SetArea(x, y, x, y)
        res = self.Select()
        if res.GetNumberOfNodes() > 0:
            # only get the first one...
            node = res.GetNode(0)
            prop = node.GetProperties()
            id = node.GetSelectionList().GetValue(0)

            key = vtkSelectionNode.PROP()
            if prop.Has(key):
                actor = key.Get(prop)
                # check if it is an instance actor...
                if hasattr(actor, 'scene'):
                    return actor, id
        return None, None

# 鼠标控制


class mouseInteractorEvent(vtkInteractorStyleMultiTouchCamera):
    def __init__(self, parent, webState, webCtrl):
        self.parent = parent
        self.webState = webState
        self.webCtrl = webCtrl

        self.showRightClickMenu = False  # 右键显示菜单栏的标志

        self.wheelCount = 0  # 鼠标滚轮处理选中模型半透明的计数器

        # 注册事件
        self.AddObserver("LeftButtonPressEvent", self.onLeftButtonDown)
        self.AddObserver("RightButtonPressEvent", self.onRightButtonDown)
        self.AddObserver("MouseWheelBackwardEvent", self.OnMouseWheelBackward)
        self.AddObserver("MouseWheelForwardEvent", self.OnMouseWheelForward)

        # 记录上一次左键按下的时间戳和位置
        self.last_left_button_press_time = 0.0
        self.last_left_button_press_position = (0, 0)

        # 石老师所写的外轮廓边缘描绘示例代码
        self.picker = SceneNodePicker()
        self.lastPick = None
        # renderers
        self.outline = None

    def SetDefaultRenderer(self, renderer):
        self.picker.SetRenderer(renderer)
        super().SetDefaultRenderer(renderer)

    def SetOutlineRenderer(self, renderer):
        self.outline = renderer

    # 鼠标左键
    def onLeftButtonDown(self, obj, event):
        current_time = vtk.vtkTimerLog.GetUniversalTime()
        current_position = self.GetInteractor().GetEventPosition()

        # 处理单击和双击事件
        if (
            current_time - self.last_left_button_press_time < 0.5 and
            current_position == self.last_left_button_press_position
        ):
            print("Double Click")
            if self.webState.sceneKey == 'device':
                self.outline.Clear()
                self.lastPick = None
                self.parent.product.enterScene()
        else:
            self.last_left_button_press_time = current_time
            self.last_left_button_press_position = current_position

            # 只要右键菜单栏打开，无论点击何处均应该关闭
            if (self.showRightClickMenu == 1):
                self.showRightClickMenu = 0
                with self.webState:
                    self.webState.rightMenuStyle = {"display": "none"}

            if self.webState.sceneKey != 'product':  # 产品场景不做精准拾取
                actor, id = self.picker.Pick(
                    current_position[0], current_position[1])
                if actor == None or id == None:
                    self.outline.Clear()
                    self.lastPick = None
                else:
                    scene = actor.scene
                    node = actor.GetNode(id)
                    self.outline.Clear()
                    self.outline.AddSceneNode(scene, node)
                    self.lastPick = [scene, node]

                    if self.webState.sceneKey == 'productline':
                        # return
                        modelList = ["model/device/Soldier.glb",
                                     "model/device/jixiebi.glb"]
                        random_integer = random.randint(0, 1)
                        modelPath = modelList[random_integer]
                        self.parent.productline.splitRenderWindow.mouseInteractorEvent.outline.Clear()
                        self.parent.productline.splitRenderWindow.mouseInteractorEvent.lastPick = None
                        self.parent.productline.splitRenderWindow.renderer.ClearScene()
                        self.parent.productline.splitScene = self.parent.productline.splitRenderWindow.LoadModel(
                            modelPath)

                        self.parent.productline.splitScene.SetActiveAnimation(
                            -1)
                        if random_integer == 0:
                            random_integer = random.randint(0, 1)  # 在取一个随机动画
                            self.parent.productline.splitScene.SetActiveAnimation(
                                random_integer)
                        else:
                            self.parent.productline.splitScene.SetActiveAnimation(
                                0)
                    elif self.webState.sceneKey == 'factory':
                        self.webCtrl.sendParentMsg(
                            {"eventScene": "factory", "eventName": "workshop_pickup", "pickActor": actor})

            self.OnLeftButtonDown()
            self.webCtrl.view_update()
            self.webCtrl.view_update()
            return

    # 鼠标右键
    def onRightButtonDown(self, obj, event):

        # 打开菜单栏
        if (self.webState.sceneKey == 'device'):
            if (self.showRightClickMenu == 0):
                self.showRightClickMenu = 1
                mouse = self.parent.interactor.GetEventPosition()
                with self.webState:
                    self.webState.rightMenuStyle = {
                        "position": "absolute",
                        "left": f"{(mouse[0] * self.webState.devicePixelRatio )}px",
                        "bottom": f"{(mouse[1]* self.webState.devicePixelRatio )}px",
                        "zIndex": 9999,
                    }
            else:
                self.showRightClickMenu = 0
                with self.webState:
                    self.webState.rightMenuStyle = {"display": "none"}
            self.OnRightButtonDown()
        return

    # 鼠标滚轮向后
    def OnMouseWheelBackward(self, obj, event):
        self.wheelCount -= 1
        # show_all()
        if self.wheelCount <= 0:
            self.setOpacity('none')
        return super().OnMouseWheelBackward()

    # 鼠标滚轮向前
    def OnMouseWheelForward(self, obj, event):
        self.wheelCount += 1
        if self.wheelCount >= 3:
            self.setOpacity('show')

        return super().OnMouseWheelForward()

    # 找到当前组件序号
    def get_index(self, actor):
        actor_collection = self.parent.currentRenderer.GetActors()
        for i in range(actor_collection.GetNumberOfItems()):
            if (actor == actor_collection.GetItemAsObject(i)):
                return i
        return -1

    # 隐藏当前组
    def hideActor(self):
        self.showRightClickMenu = 0

        if self.lastPick:
            scene, node = self.lastPick
            node.SetVisible(not node.visible)
            self.outline.Clear()
            self.lastPick = None
            scene.Update()
        # 隐藏菜单栏
        self.parent.currentRenderer.Render()

        with self.webState:
            self.webState.rightMenuStyle = {"display": "none"}

        self.webCtrl.view_update()

    # 显示所有组件
    def showAllActor(self):
        self.showRightClickMenu = 0

        sceneList = None
        if self.webState.sceneKey == "productline":
            sceneList = self.parent.productline.sceneList
            for scene in sceneList:
                scene.SetVisible(1)
                scene.Update()

        if self.webState.sceneKey == "device":
            scene = self.parent.device.scene
            scene.SetVisible(1)
            scene.Update()

        # 隐藏菜单栏
        with self.webState:
            self.webState.rightMenuStyle = {"display": "none"}
        self.webCtrl.view_update()

    # 设置透明度
    def setOpacity(self, option):
        print('滚轮半透明已失效')
        # 半透明无效，需石老师重新提供代码
        # if self.lastPick :
        #     scene, node = self.lastPick
        #     if option == 'show':
        #         node.GetProperty().SetOpacity(0.4)
        #     else:
        #         node.GetProperty().SetOpacity(1)
